<template>
  <div class="main">
    <div class="box">
      <div class="left">
        <el-card class="box-card">
          <p>选择数据源：</p>
          <el-select
            v-model="dataSourceValue"
            style="width: 100%"
            placeholder="请选择数据源"
            @change="handleChangeDataSource"
          >
            <el-option
              v-for="item in listDataSource"
              :key="item.id"
              :label="item.dataSourceName"
              :value="item.id"
            />
          </el-select>
          <p>数据库结构：</p>
          <div class="source_box">
            <div v-if="dataSourceValue">
              <el-input v-model="filterText" placeholder="输入关键字进行过滤" />
              <el-tree
                ref="tree"
                :props="defaultProps"
                draggable
                :check-on-click-node="true"
                :highlight-current="true"
                :data="data"
                node-key="key"
                :filter-node-method="filterNode"
                lazy
                :load="loadNode"
                class="filter-tree"
                show-checkbox
                @check="handleCheck"
              >
                <span
                  v-if="!node.isLeaf"
                  slot-scope="{ node, data }"
                  class="tree-title"
                >{{ data.label }}</span>
                <el-tooltip
                  v-else
                  slot-scope="{ data }"
                  class="item"
                  effect="dark"
                  :content="data.label"
                  placement="top-start"
                >
                  <span class="tree-title">{{ data.label }}</span>
                </el-tooltip>
              </el-tree>
            </div>
            <div v-else>
              <el-empty description="选择上方数据源" :image-size="50" />
            </div>
          </div>
        </el-card>
      </div>
      <div class="right">
        <el-card>
          <div slot="header" class="clearfix">
            <span>SQL生成</span>
          </div>
          <div class="field-box">
            <div v-if="fieldNodeList.length > 0" class="field-item">
              <p
                v-for="(item, index) in fieldNodeList"
                :key="index"
                class="field-item_title"
              >
                <span class="field-item_title_icon">
                  <span class="field-item_title_icon_text">
                    <svg
                      t="1732247439481"
                      class="icon"
                      viewBox="0 0 1024 1024"
                      version="1.1"
                      xmlns="http://www.w3.org/2000/svg"
                      p-id="7161"
                      width="15"
                      height="15"
                    >
                      <path
                        d="M757.540571 626.936686H548.571429a36.571429 36.571429 0 1 1 0-73.142857h208.983771a36.571429 36.571429 0 0 1 0 73.142857z m0-151.508115H548.571429a36.571429 36.571429 0 1 1 0-73.142857h208.983771a36.571429 36.571429 0 0 1 0 73.142857z m0-146.285714h-104.491885a36.571429 36.571429 0 1 1 0-73.142857h104.491885a36.571429 36.571429 0 0 1 0 73.142857z m-229.873371 0h-94.032457v292.571429a36.571429 36.571429 0 0 1-73.142857 0v-292.571429h-94.047086a36.571429 36.571429 0 0 1 0-73.142857h261.2224a36.571429 36.571429 0 0 1 0 73.142857z m-256 365.714286h485.873371a36.571429 36.571429 0 0 1 0 73.142857H271.6672a36.571429 36.571429 0 0 1 0-73.142857z"
                        fill="#333333"
                        p-id="7162"
                      /></svg>{{ item.name }}</span>
                  <svg
                    t="1732247476951"
                    class="icon"
                    viewBox="0 0 1024 1024"
                    version="1.1"
                    xmlns="http://www.w3.org/2000/svg"
                    p-id="8158"
                    width="15"
                    height="15"
                    style="cursor: pointer"
                    @click="deleteField(item)"
                  >
                    <path
                      d="M806.4 263.2l-45.6-45.6L512 467.2 263.2 217.6l-45.6 45.6L467.2 512 217.6 760.8l45.6 45.6L512 557.6l248.8 248.8 45.6-45.6L557.6 512z"
                      p-id="8159"
                      fill="#000000"
                    />
                  </svg>
                </span>
              </p>
            </div>
            <div v-else class="empty">
              <img src="@/assets/images/selectfield.png" alt="勾选字段">
              <p>请选择左侧数据源并勾选字段</p>
            </div>
          </div>
          <el-card v-if="fieldNodeList.length > 0">
            <p style="font-weight: 600">高级配置：</p>
            <el-form ref="form" :model="form" label-width="80px">
              <el-form-item label="分页设置">
                <el-input v-model="form.limit" style="width: 60%" />
                <el-select
                  v-model="limitValue"
                  placeholder="请选择"
                  style="margin-left: 10px"
                  @change="handleLimitChange"
                >
                  <el-option
                    v-for="item in limitOption"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  />
                </el-select>
              </el-form-item>
            </el-form>
            <div class="btn-box">
              <el-button
                type="primary"
                @click="handleGenerateSql"
              >生成SQL</el-button>
            </div>
          </el-card>
        </el-card>

        <el-card v-if="currentTableData">
          <div slot="header" class="clearfix">
            <span>原SQL</span>
          </div>
          <CodeEditor
            ref="sqlEditor"
            :key="sql.length"
            :editor-hight="150"
            :code-data="currentTableData.row.selectSQL"
            :value-font-size="12"
          />
        </el-card>

      </div>
    </div>
    <el-dialog title="SQL编辑" width="1100px" :visible.sync="sqlEditDialog" :modal="false">
      <CodeEditor
        ref="sqlEditor"
        :key="sql.length"
        :editor-hight="400"
        :code-data="sql"
        :value-font-size="12"
      />
      <div slot="footer" class="dialog-footer">
        <el-button
          type="primary"
          @click="sqlEditDialog = false"
        >确 定</el-button>
        <el-button
          type="primary"
          @click="handleGenerateSqlSave"
        >保存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {
  listDatasourceInfo,
  databaseListDatabaseAndSchema,
  databaseListObjects,
  databaseListDbColumns
} from '@/api/console/datasourceInfo'
import CodeEditor from '@/components/CodeEditor/index.vue'

export default {
  name: 'SqlGenerate',
  components: { CodeEditor },
  props: ['dataSourceId', 'formData', 'currentTableData'],
  data() {
    return {
      form: {
        limit: 'OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;'
      },
      listDataSource: [],
      dataSourceValue: '',
      filterText: '',
      data: [],
      defaultProps: {
        children: 'children',
        label: 'label',
        isLeaf: 'leaf'
      },
      databaseName: null,
      fieldNodeList: [],
      sqlEditDialog: false,
      sql: '',
      limitOption: [
        {
          label: '模板一',
          value: 'OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;'
        },
        {
          label: '模板二',
          value: 'LIMIT 10 OFFSET 10;'
        }
      ],
      limitValue: 'OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;',
      dataFilter: {
        tables: [],
        fields: []
      }
    }
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val)
    },
    data() {
      setTimeout(() => {
        this.deleteCheck()
      }, 50)
    }
  },
  async created() {
    this.getDatabaseList()
    if (this.$props.dataSourceId) {
      this.dataSourceValue = this.$props.dataSourceId
      this.handleChangeDataSource(this.dataSourceValue)
    }
    if (this.$props.formData && !this.$props.formData.tableBatchConf) {
      this.$props.formData.tableBatchConf = []
    }
  },
  methods: {
    handleGenerateSqlSave() {
      const insertColumns = []
      this.dataFilter.fields.forEach((f) => {
        insertColumns.push(f.split('AS')[1].trim().slice(0, -1))
      })
      const currentData = {
        selectSQL: this.sql,
        insertColumns,
        tableName: this.$props.currentTableData ? this.$props.currentTableData.row.tableName : ''
      }

      if (this.$props.currentTableData) {
        this.$props.formData.tableBatchConf[this.$props.currentTableData.$index] = currentData
        this.$props.currentTableData = null
      } else {
        this.$props.formData.tableBatchConf.push(currentData)
      }
      return this.$message.success('保存成功')
    },
    handleLimitChange(_v) {
      this.form.limit = _v
    },
    handleGenerateSql() {
      const tenantIdMenus = [
        ...this.$refs.tree.getCheckedKeys(),
        ...this.$refs.tree.getHalfCheckedKeys()
      ]
      const parentNodes = tenantIdMenus.filter(
        (f) => this.$refs.tree.getNode(f).data.isParent
      )
      parentNodes.forEach((parentKey) => {
        const parentNode = this.$refs.tree.getNode(parentKey)
        this.dataFilter.tables.push(parentKey)

        const fieldsForParent = parentNode.childNodes
          .filter(
            (childNode) =>
              tenantIdMenus.includes(childNode.data.key) && childNode.checked
          )
          .map(
            (childNode) =>
              `${parentKey}.${childNode.data.key} AS ${childNode.data.key}`
          )

        this.dataFilter.fields.push(...fieldsForParent)
      })
      this.sql = this.sqlFormatter
        .format(`SELECT ${this.dataFilter.fields.join(
          ','
        )}\n FROM ${this.dataFilter.tables.join(',')}\n
      ${this.form.limit}`)
      this.sqlEditDialog = true
    },
    waitLazyLoaded(targetNode) {
      return new Promise((resolve, reject) => {
        targetNode.expand()
        resolve()
      })
    },
    handleCheck(selection) {
      if (!(selection.children && selection.children.length > 0)) {
        const targetNode = this.$refs.tree.getNode(selection)
        this.waitLazyLoaded(targetNode).then(() => {
          setTimeout(() => {
            this.fieldNodeList = this.$refs.tree.getCheckedNodes(true)
          }, 100)
        })
      } else {
        this.fieldNodeList = this.$refs.tree.getCheckedNodes(true)
      }
    },
    async getDatabaseList() {
      const res = await listDatasourceInfo({
        pgNum: 1,
        pgSize: 999,
        dataType: '2'
      })
      this.listDataSource = res.rows
    },
    async handleChangeDataSource(e) {
      this.data = []
      try {
        const { data } = await databaseListDatabaseAndSchema({
          id: e
        })

        if (data.code !== 200) {
          return this.$message.error(data.msg)
        }
        data.data.forEach((e) => {
          this.data.push({
            key: e.database,
            label: e.database,
            disabled: true,
            isParent: false
          })
        })
      } catch (error) {
        console.info(error)
      }
    },
    async loadNode(node, resolve) {
      let res = null
      const children = []
      if (node.level > 0) {
        if (node.level === 1) {
          this.databaseName = node.data.label
        }
        res = await databaseListObjects({
          id: this.dataSourceValue,
          taskMode: 'all',
          databaseName: this.databaseName
        })
      }
      if (node.level === 1) {
        const dictValue = await this.getDicts('appraise_taskmode')
        Object.keys(res.data.data).forEach((e) => {
          const label = dictValue.data.find((f) => f.dictValue === e).dictLabel
          children.push({
            key: e,
            label: label,
            name: label,
            disabled: true,
            isParent: false
          })
        })
      }
      if (node.level === 2) {
        res.data.data[node.data.key].forEach((e) => {
          const name = `${node.data.key}Name`
          children.push({
            key: e[name],
            label: e[name],
            name: e[name],
            parent: node.data.key,
            isParent: true
          })
        })
      }
      if (node.level === 3) {
        const res = await databaseListDbColumns({
          id: this.dataSourceValue,
          tableNames: [node.data.key],
          databaseName: this.databaseName,
          isParent: false
        })
        if (res.data.data[node.data.key]) {
          res.data.data[node.data.key].forEach((f) => {
            children.push({ name: f, key: f, label: f, leaf: true })
          })
        }
      }
      resolve(children)
      setTimeout(() => {
        this.deleteCheck()
      }, 50)
    },
    filterNode(value, data) {
      if (!value) return true
      return data.label.indexOf(value) !== -1
    },
    deleteCheck(e) {
      const el = document.querySelectorAll('.is-disabled')
      el.forEach((f) => {
        f.remove()
      })
    },
    deleteField(item) {
      this.$refs.tree.setChecked(item, false)
      this.fieldNodeList = this.$refs.tree.getCheckedNodes(true)
    }
  }
}
</script>
<style lang="scss" scoped>
.main {
  width: 100%;
  height: 100%;
  .box {
    width: 98%;
    height: 98%;
    margin: 0 auto;
    padding: 10px;
    display: flex;
    .left {
      width: 25%;
      height: 100%;
      max-width: 300px;

      .box-card {
        height: 100%;

        p {
          margin: 10px 0;
          font-size: 13px;
          opacity: 0.8;
        }

        .source_box {
          width: 100%;
          padding: 10px;
          border: 1px solid #ccc;
          flex: 1;
          overflow: auto;
          .filter-tree {
            margin: 10px 0;

            .tree-title {
              color: #666;
              font-size: 14px;
            }
          }
        }
      }
    }

    .right {
      margin-left: 15px;
      width: 80%;
      .field-box {
        padding: 10px;
        .field-item {
          width: 100%;
          margin: 0 auto;
          background-color: #ccc;
          min-height: 200px;
          border-radius: 10px;
          padding: 5px;

          .field-item_title {
            display: inline-block;
            background: #fff;
            margin: 5px;
            border-radius: 5px;

            &:hover {
              box-shadow: 0px 0px 5px 0px #555;
            }

            .field-item_title_icon {
              display: flex;
              align-items: center;
              justify-content: space-between;
              padding: 5px;

              .field-item_title_icon_text {
                display: flex;
                margin-right: 10px;
                align-items: center;
                font-size: 12px;
                font-weight: 600;
                color: #555;
              }
            }
          }

          .field-item-tips {
            color: #000;
          }
        }
        .empty {
          margin: 30px 0;
          display: flex;
          align-items: center;
          flex-direction: column;
          img {
            width: 50px;
          }
          p {
            font-size: 14px;
            color: #909399;
          }
        }
      }

      .btn-box {
        padding-left: 10px;
      }
    }
  }
}
</style>
<style scoped>
::v-deep .el-card__body {
  height: 100%;
  display: flex;
  flex-direction: column;
}
</style>
